<script setup lang="ts">
import WaveDecoder from 'common/src/utils/weatherDecoder/WaveDecoder';
import WindDecoder from 'common/src/utils/weatherDecoder/WindDecoder';
import CurrentDecoder from 'common/src/utils/weatherDecoder/CurrentDecoder';
import VisibilityDecoder from 'common/src/utils/weatherDecoder/VisibilityDecoder';
import SstDecoder from 'common/src/utils/weatherDecoder/SstDecoder';
import PressureDecoder from 'common/src/utils/weatherDecoder/PressureDecoder';
import PrecipDecoder from 'common/src/utils/weatherDecoder/PrecipDecoder';
import { useTaskStore, useTimeRangeStore, useWeatherStore } from '@/store';
import {getAngleText, WeatherType, getNMFromMeter, getLocalWeatherUrl} from 'common/src/utils/weather';
import { MapMouseEvent, Marker } from 'mapbox-gl';
import { toLonLatString } from 'common/src/utils/lnglat';
import { Map as MapboxMap } from 'mapbox-gl';
import { CloseBold } from '@element-plus/icons-vue';
import { ElIcon } from 'element-plus';

interface WeatherInfo {
  lat: number;
  lon: number;
  latLng: string;
  windSpd: number | '';
  windAngle: number | '';
  windDirection: string;
  currentSpd: number | '';
  currentAngle: number | '';
  currentDirection: string;
  waveHeight: number | '';
  waveAngle: number | '';
  waveDirection: string;
  sst: number | '';
  visibility: number | '';
  pressure: number | '';
  precip: number | '';
}

interface Props {
  active: boolean;
}

const props = defineProps<Props>();
const taskStore = useTaskStore();
const waveDecoder = new WaveDecoder();
const windDecoder = new WindDecoder();
const currentDecoder = new CurrentDecoder();
const visibilityDecoder = new VisibilityDecoder();
const sstDecoder = new SstDecoder();
const pressureDecoder = new PressureDecoder();
const precipDecoder = new PrecipDecoder();
const timeRangeStore = useTimeRangeStore();
const weatherStore = useWeatherStore();
const spotWeatherPopContent = ref<HTMLDivElement | null>(null);
const spotWeatherMarker = ref<Marker | null>(null);
const markerAdded = ref(false);
const isFlipped = ref(false); // 反转标识：内容在点位下方时为 true
// 当前旗标的锚点；默认在点的下方显示内容（即内容在上方）
const currentAnchor = ref<'bottom-left' | 'top-left'>('bottom-left');

const weatherInfo = reactive<WeatherInfo>({
  lat: 0,
  lon: 0,
  latLng: '',
  windSpd: '',
  windAngle: '',
  windDirection: '',
  currentSpd: '',
  currentAngle: '',
  currentDirection: '',
  waveHeight: '',
  waveAngle: '',
  waveDirection: '',
  sst: '',
  visibility: '',
  pressure: '',
  precip: '',
});

const updateWindData = (lng: number, lat: number) => {
  const windInfo = windDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.windSpd = windInfo?.speed ?? '';
  weatherInfo.windAngle = windInfo?.angle ?? '';
  weatherInfo.windDirection = windInfo?.angle === undefined ? '' : getAngleText(windInfo.angle);
};

const updateCurrentData = (lng: number, lat: number) => {
  const currentInfo = currentDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.currentSpd = currentInfo?.speed ?? '';
  weatherInfo.currentAngle = currentInfo?.angle ?? '';
  weatherInfo.currentDirection =
    currentInfo?.angle === undefined ? '' : getAngleText(currentInfo.angle);
};

const updateWaveData = (lng: number, lat: number) => {
  const waveInfo = waveDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.waveHeight = waveInfo?.height ?? '';
  weatherInfo.waveAngle = waveInfo?.angle ?? '';
  weatherInfo.waveDirection = waveInfo?.angle === undefined ? '' : getAngleText(waveInfo.angle);
};

const updateSSTData = (lng: number, lat: number) => {
  const sstInfo = sstDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.sst = sstInfo?.value ?? '';
};

const updateVisibilityData = (lng: number, lat: number) => {
  const visibilityInfo = visibilityDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.visibility = visibilityInfo?.value ?? '';
};

const updatePressureData = (lng: number, lat: number) => {
  const pressureInfo = pressureDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.pressure = pressureInfo?.value ?? '';
};

const updatePrecipData = (lng: number, lat: number) => {
  const precipInfo = precipDecoder.decodeByLngLat([lng, lat]);
  weatherInfo.precip = precipInfo?.value ?? '';
};

const handleGetPointWeather = (e: MapMouseEvent) => {
  const { lng, lat } = e.lngLat || spotWeatherMarker.value?.getLngLat();
  // 计算点击点在视窗内的像素 y，用于判断是否需要“倒置显示”
  let pixelY: number | undefined = (e as any)?.point?.y;
  if (pixelY === undefined && weatherStore.map) {
    // 回退：根据经纬度投影到像素坐标
    const proj = (weatherStore.map as MapboxMap).project([lng, lat]);
    pixelY = proj?.y as number;
  }
  // 顶部 150px 内倒置显示（标题 44px + 旗标约 88px，留一点余量）
  const needFlip = typeof pixelY === 'number' && pixelY < 150;
  const wantAnchor: 'bottom-left' | 'top-left' = needFlip ? 'top-left' : 'bottom-left';
  isFlipped.value = wantAnchor === 'top-left';
  if (wantAnchor !== currentAnchor.value) {
    recreateSpotMarker(wantAnchor);
  }
  weatherInfo.lat = lat;
  weatherInfo.lon = lng;
  weatherInfo.latLng = toLonLatString(lng, lat);
  updateWindData(lng, lat);
  updateCurrentData(lng, lat);
  updateWaveData(lng, lat);
  updateSSTData(lng, lat);
  updateVisibilityData(lng, lat);
  updatePressureData(lng, lat);
  updatePrecipData(lng, lat);
  // console.log(res?.speed, res?.angle, res?.rgba);
  spotWeatherMarker.value?.setLngLat([lng, lat]);
  if (!markerAdded.value) {
    spotWeatherMarker.value?.addTo(weatherStore.map as any);
    markerAdded.value = true;
  }
};

const weatherDecoderUpdatedCallback = (updateFn: (lng: number, lat: number) => void) => {
  return () => {
    if (markerAdded.value) {
      const { lng, lat } = spotWeatherMarker.value?.getLngLat()!;
      updateFn(lng, lat);
    }
  };
};

const updateWeatherDecoder = (time: number) => {
  const taskStore = useTaskStore();
  let windUrl = getLocalWeatherUrl(WeatherType.wind, time);
  windUrl = taskStore.replaceUrlDir(windUrl)
  windDecoder.updateWeather(windUrl, weatherDecoderUpdatedCallback(updateWindData));

  let waveUrl = getLocalWeatherUrl(WeatherType.seawave, time);
  waveUrl = taskStore.replaceUrlDir(waveUrl)
  waveDecoder.updateWeather(waveUrl, weatherDecoderUpdatedCallback(updateWaveData));

  let currentUrl = getLocalWeatherUrl(WeatherType.seacurrents, time);
  currentUrl = taskStore.replaceUrlDir(currentUrl)
  currentDecoder.updateWeather(currentUrl, weatherDecoderUpdatedCallback(updateCurrentData));

  let visibilityUrl = getLocalWeatherUrl(WeatherType.visibility, time);
  visibilityUrl = taskStore.replaceUrlDir(visibilityUrl)
  visibilityDecoder.updateWeather(visibilityUrl, weatherDecoderUpdatedCallback(updateVisibilityData));

  let sstUrl = getLocalWeatherUrl(WeatherType.sst, time);
  sstUrl = taskStore.replaceUrlDir(sstUrl)
  sstDecoder.updateWeather(sstUrl, weatherDecoderUpdatedCallback(updateSSTData));

  let pressureUrl = getLocalWeatherUrl(WeatherType.pressure, time);
  pressureUrl = taskStore.replaceUrlDir(pressureUrl)
  pressureDecoder.updateWeather(pressureUrl, weatherDecoderUpdatedCallback(updatePressureData));

  let precipUrl = getLocalWeatherUrl(WeatherType.precipitation, time);
  precipUrl = taskStore.replaceUrlDir(precipUrl)
  precipDecoder.updateWeather(precipUrl, weatherDecoderUpdatedCallback(updatePrecipData));
};

const removeSpotMarker = () => {
  spotWeatherMarker.value?.remove();
  markerAdded.value = false;
};

const startDecoder = (map: MapboxMap) => {
  map.on('click', handleGetPointWeather);
};

const endDecoder = (map: MapboxMap) => {
  map.off('click', handleGetPointWeather);
  spotWeatherMarker.value?.remove();
  markerAdded.value = false;
};

watch(() => timeRangeStore.currentTime, (val) => {
  if (!weatherStore.climateLayerActive) {
    setTimeout(() => {
      updateWeatherDecoder(val);
    }, 0);
  }
}, { immediate: true });

watch([
  () => taskStore.infoShow.routePoint,
  () => taskStore.infoShow.regionWxMsg,
  () => taskStore.infoShow.attitudeDecoder,
], (val) => {
  if (val.some(item => item)) {
    removeSpotMarker();
  }
});

onMounted(() => {
  spotWeatherMarker.value = new Marker({
    className: 'marker-popup spot-weather-marker',
    draggable: true,
    element: spotWeatherPopContent.value! as HTMLDivElement,
    anchor: currentAnchor.value,
    offset: [-2, -1],
  });
  // @ts-ignore
  (spotWeatherMarker.value as any).on('drag', handleGetPointWeather);
});

onBeforeUnmount(() => {
  // @ts-ignore
  (spotWeatherMarker.value as any).off('drag', handleGetPointWeather);
});

defineExpose({
  startDecoder,
  endDecoder,
});

// ============== 辅助：根据需要重建旗标以切换锚点（上下翻转） ==============
function recreateSpotMarker(anchor: 'bottom-left' | 'top-left') {
  if (currentAnchor.value === anchor && spotWeatherMarker.value) return;
  // 解绑旧事件并移除
  try { (spotWeatherMarker.value as any)?.off?.('drag', handleGetPointWeather); } catch {}
  spotWeatherMarker.value?.remove();
  markerAdded.value = false;
  // 使用同一个 DOM 元素重新创建 Marker
  spotWeatherMarker.value = new Marker({
    className: 'marker-popup spot-weather-marker',
    draggable: true,
    element: spotWeatherPopContent.value! as HTMLDivElement,
    anchor,
    offset: [-2, -1],
  });
  // @ts-ignore
  (spotWeatherMarker.value as any).on('drag', handleGetPointWeather);
  isFlipped.value = anchor === 'top-left';
  currentAnchor.value = anchor;
}
</script>

<template>
  <div v-show="props.active && markerAdded" class="spot-weather-top">
    <div>经纬度: {{ weatherInfo.latLng }}</div>
    <div>
      流: {{ weatherInfo.currentSpd === '' ? '' : weatherInfo.currentDirection || '--' }}
      {{ weatherInfo.currentSpd === '' ? '--' : `${weatherInfo.currentSpd}kts` }}
      {{ weatherInfo.currentAngle === '' ? '' : `${weatherInfo.currentAngle}°` }}
    </div>
    <div>降雨: {{ weatherInfo.precip === '' ? '--' : `${weatherInfo.precip}mm` }}</div>
    <div>海温: {{ weatherInfo.sst === '' ? '--' : `${weatherInfo.sst}℃` }}</div>
    <div>气压: {{ weatherInfo.pressure === '' ? '--' : `${weatherInfo.pressure}hPa` }}</div>
    <div>能见度: {{ weatherInfo.visibility === '' ? '--' : `${getNMFromMeter(weatherInfo.visibility * 1000).toFixed(1)}nm` }}</div>
  </div>
  <div ref="spotWeatherPopContent" class="spot-weather-content" :class="{ 'spot-weather-flipped': isFlipped }">
    <div class="spot-weather-flag">
      <div>
        风: {{ weatherInfo.windDirection || '--' }}
        {{ weatherInfo.windSpd === '' ? '--' : `${weatherInfo.windSpd}kts` }}
        {{ weatherInfo.windAngle === '' ? '--' : `${weatherInfo.windAngle}°` }}
      </div>
      <div>
        浪: {{ weatherInfo.waveHeight === '' ? '' : weatherInfo.waveDirection || '--' }}
        {{ weatherInfo.waveHeight === '' ? '--' : `${weatherInfo.waveHeight}m` }}
        {{ weatherInfo.waveAngle === '' ? '' : `${weatherInfo.waveAngle}°` }}
      </div>
      <ElIcon
        class="spot-weather-close"
        @click.stop="() => removeSpotMarker()"
      ><CloseBold /></ElIcon>
    </div>
    <div class="spot-weather-dot" />
  </div>
</template>

<style lang="less">
.spot-weather-top {
  position: absolute;
  top: 0;
  right: 60px;
  max-width: calc(100vw - 60px - 460px);
  display: flex;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.7);
  font-size: 12px;
  padding: 4px 6px;
  border-radius: 4px;
  z-index: 10;
  &>*:not(:last-child) {
    margin-right: 6px;
  }
  .spot-weather-top-close {
    padding-top: 2px;
    margin-left: 2px;
    cursor: pointer;
    align-self: flex-start;
  }
}
.spot-weather-content {
  display: none;
  position: absolute;
  width: fit-content;
  color: #fffefe;
  font-size: 13px;
  user-select: text;
  border-left: 2px solid #4d4d4d;
  padding-bottom: 40px;
  // pointer-events: none;
  .spot-weather-flag {
    padding: 4px 8px 4px 4px;
    background-color: #4d4d4d;
    border-radius: 0 14px 14px 0;
    width: fit-content;
  }
  .spot-weather-dot {
    position: absolute;
    width: 8px;
    height: 8px;
    background-color: #fff;
    border-radius: 50%;
    bottom: -5px;
    left: -5px;
  }
  .spot-weather-close {
    position: absolute;
    right: -12px;
    top: -4px;
    font-size: 14px;
    padding: 1px;
    background-color: #4d4d4d;
    border-radius: 50%;
    cursor: pointer;
  }
}
.mapboxgl-map .spot-weather-content {
  display: block;
}
.marker-popup {
  color: #fffefe;
  .mapboxgl-popup-content {
    background: rgba(0, 0, 0, 0.7);
    border-radius: 5px;
    padding: 9px;
  }
  .mapboxgl-popup-tip {
    border-width: 6px;
  }
  &.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip {
    border-top-color: rgba(0, 0, 0, 0.7);
  }
  &.mapboxgl-popup-anchor-top .mapboxgl-popup-tip {
    border-bottom-color: rgba(0, 0, 0, 0.7);
  }
  &.mapboxgl-popup-anchor-right .mapboxgl-popup-tip {
    border-left-color: rgba(0, 0, 0, 0.7);
  }
  &.mapboxgl-popup-anchor-left .mapboxgl-popup-tip {
    border-right-color: rgba(0, 0, 0, 0.7);
  }
  .mapboxgl-popup-close-button {
    color: #fff;
    font-size: 16px;
    line-height: 16px;
    padding: 0 3px;
  }
}

/* 提供翻转时可定制的样式钩子（默认不做视觉修改） */
.spot-weather-content.spot-weather-flipped {
  padding-bottom: 0;
  padding-top: 40px;
  .spot-weather-dot {
    bottom: auto !important;
    top: -5px !important;
  }
  .spot-weather-close {
    bottom: 44px !important;
    top: auto !important;
  }
}
</style>
